package sap;
import java.io.PrintStream;
import java.util.HashMap;

import sap.provider.PSP;
import sap.provider.Project;
import sap.provider.Stone;

import com.sap.mw.jco.IFunctionTemplate;
import com.sap.mw.jco.JCO;
import com.sap.mw.jco.JCO.Client;
import com.sap.mw.jco.JCO.Function;
import com.sap.mw.jco.JCO.Repository;

import data.Milestone;
import data.PSPElement;
import data.ProjectDefinition;

/**
 * 
 */



public final class Connection {

	private static Connection instance = null;
	
	private final Client mConnection;
	private final Repository mRepository;
	
	private final HashMap<String, IFunctionTemplate> templates
		= new HashMap<String, IFunctionTemplate>();
	
	public PrintStream logger = System.out;

	public Connection(String clientSAP, String login, String passwd, String language,
			String server, String systemNumber) {
		mConnection = JCO.createClient(clientSAP, login, passwd, language,
				server, systemNumber);
		mConnection.connect();
		
		mRepository = new Repository("Default", mConnection);
		
		instance = this;
	}
	
	/**
	 * Returns a {@link JCO.Function} for the given function name
	 * 
	 * @param fbName the name of the SAP BAPI
	 * @return the {@link JCO.Function}
	 * @throws JCO.Exception if an error occurred during the retrieval of the
	 *  function interface.
	 */
	public Function getFunction(String fbName)
			throws JCO.Exception {
		IFunctionTemplate ft = templates.get(fbName);
		
		if (ft == null) {
			// Function called for the first time
			ft = mRepository.getFunctionTemplate(fbName);
			templates.put(fbName, ft);
		}
		
		return ft.getFunction();
	}
	
	/**
	 * 
	 * @param function
	 * @throws JCO.AbapException
	 * @throws JCO.Exception
	 * @see JCO.Connection.execute
	 */
	public void execute(JCO.Function function)
			throws JCO.AbapException, JCO.Exception {
		logger.println("Executing function: " + function.getName());
		// TODO maybe we need more logs
		mConnection.execute(function);
	}
	
	public static void fillX(JCO.Record struct)
			throws JCO.ConversionException {
		fillX(struct, 0);
	}
	
	public static void fillX(JCO.Record struct, int start)
			throws JCO.ConversionException {
		int num = struct.getNumFields();
		for (int i=start; i<num; i++) {
			struct.setValue("X", i);
		}
	}
	
	public String getLanguage() {
		return mConnection.getAttributes().getLanguage();
	}

	public void disconnect() {
		if (mConnection.isAlive())
			mConnection.disconnect();
	}
	
	public static void testRun() {
		ProjectDefinition project = new ProjectDefinition();
		project.project_definition = "I/4080";
		PSPElement psp;
		Milestone stone;
			
		final long sleepTime = 2500;

		try {
			// create project
			project.description = "Test Project";
			project.project_profile = "0001";
			
			Project.create(project);
			Thread.sleep(sleepTime);
			
			// modify project
			project = Project.get(project.project_definition);
			project.description = "My new Test Project";
			
			Project.maintain(project);
			Thread.sleep(sleepTime);
			
			// create 2 psps
			String psps[] = {"I/4080-1", "I/4080-2"};
			for (int i=0; i<2; i++) {
				psp = new PSPElement();
				psp.wbs_element = psps[i];
				psp.description = "Test PSP Element";
				psp.project_definition = project.project_definition;
				
				PSP.create(psp);
				Thread.sleep(sleepTime);
			}
			
			// modify first
			psp = PSP.get(project.project_definition, psps[0]);
			psp.description = "First PSP Element";
			
			PSP.maintain(psp);
			Thread.sleep(sleepTime);
			
			// delete first
			PSP.delete(psp);
			Thread.sleep(sleepTime);
			
			// add milestone to second
			stone = new Milestone();
			stone.wbs_element = psps[1];
			stone.description = "Test milestone";
			
			Stone.create(stone);
			Thread.sleep(sleepTime);
			
		} catch (Exception ex) {
			System.err.println("Error in test run:");
			ex.printStackTrace();
			//System.err.println(ex.getMessage());
		}
		
		try {
			// delete project
			Project.delete(project.project_definition);
		} catch (Exception ex) {
		}
		
		System.out.println("Finished!");
	}
	
	public static Connection getInstance() {
		return instance;
	}
}